package org.mymybatis.core;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.mymybatis.utils.Resources;

import javax.sql.DataSource;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @program: mySSM
 * @description: SqlSession工厂类构建器
 * @author:wjp
 * @create: 2025-02-15 22:57
 **/
public class SqlSessionFactoryBuilder {
    /**
     * 构建SqlSessionFactory对象
     * 需要根据配置文件创建transaction对象以及MappedStatements对象
     * @param resourceAsStream
     * @return
     */
    public SqlSessionFactory build(InputStream resourceAsStream) {
        Transaction transaction = null;
        DataSource dataSource = null;
        SqlSessionFactory sqlSessionFactory = null;
        Map<String,MappedStatement> mappedStatements = null;

        // 读取配置文件
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(resourceAsStream);
            Element environmentsElt = (Element) document.selectSingleNode("/configuration/environments");
            // 获取默认启用的数据源名称
            String defaultDB = environmentsElt.attributeValue("default");
            // 获取environments标签下environment标签且id为defaultDB的标签
            Element environmentElt = (Element) document.selectSingleNode("/configuration/environments/environment[@id='" + defaultDB + "']");
            // 获取数据源节点
            Element dataSourceElt = environmentElt.element("dataSource");
            // 创建数据源对象

            dataSource = createDataSource(dataSourceElt);

            // 获取该环境下的事务管理器节点
            Element transactionManagerElt = environmentElt.element("transactionManager");
            // 创建事务管理器对象
            transaction = createTransaction(transactionManagerElt,dataSource);

            Element mappersElt = (Element) document.selectSingleNode("/configuration/mappers");
            // 创建mappedStatements对象
            mappedStatements =  createMappedStatements(mappersElt);

            sqlSessionFactory = new SqlSessionFactory(transaction, mappedStatements);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return sqlSessionFactory;
    }

    private Map<String, MappedStatement> createMappedStatements(Element mappersElt) {
        Map<String,MappedStatement> mappedStatements = new HashMap<>();
        List<Element> mapperEltList = mappersElt.elements("mapper");
        ArrayList<String> mapperXmlPathList = new ArrayList<>();
        mapperEltList.forEach(elt -> {
            mapperXmlPathList.add(elt.attributeValue("resources"));
        });

        // 根据mapperXmlPathList获取所有的xml文件
        SAXReader saxReader = new SAXReader();
        for (String mapperXmlPath : mapperXmlPathList) {
            try {
                // 具体的每一个mapper文件
                Document document = saxReader.read(Resources.getResourceAsStream(mapperXmlPath));
                Element rootElt = (Element) document.selectSingleNode("/mapper");
                // 当前mapper的namespace
                String namespace = rootElt.attributeValue("namespace");

                // 获取当前mapper文件的所有sql标签
                List<Element> sqlElementList = rootElt.elements();
                sqlElementList.forEach(elt -> {
                    String sqlId = elt.attributeValue("id");
                    String resultType = elt.attributeValue("resultType");
                    String sqlText = elt.getTextTrim();
                    MappedStatement mappedStatement = new MappedStatement();
                    mappedStatement.setResultType(resultType);
                    mappedStatement.setSqlText(sqlText);
                    mappedStatements.put(namespace + "." + sqlId, mappedStatement);
                });

            } catch (DocumentException e) {
                throw new RuntimeException(e);
            }
        }


        return mappedStatements;
    }

    private DataSource createDataSource(Element dataSourceElt) {
        UnPolledDataSource unPolledDataSource = null;
        //暂存数据源对象相关的配置属性
        Map<String,String> propertyMap = new HashMap<>(4);
        // 获取数据源类型
        String dataSourceType = dataSourceElt.attributeValue("type");
        if ("UNPOLLED".equalsIgnoreCase(dataSourceType)){
            // 创建不使用数据源的数据源对象
            List<Element> properties = dataSourceElt.elements("property");
            properties.forEach(property ->{
                propertyMap.put(property.attributeValue("name"), property.attributeValue("value"));
            });
            unPolledDataSource = new UnPolledDataSource(propertyMap.get("driver"),propertyMap.get("url"),propertyMap.get("username"),propertyMap.get("password"));
        }

        return unPolledDataSource;
    }

    private Transaction createTransaction(Element transactionManagerElt, DataSource dataSource) {
        Transaction transaction = null;
        // 获取事务管理器类型
        String transactionType = transactionManagerElt.attributeValue("type");
        if ("JDBC".equalsIgnoreCase(transactionType)){
            // 创建jdbc类型的事务管理器
            transaction = new JDBCTransaction(dataSource,false);
        }

        return transaction;
    }
}
